/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * 知启蒙Servlet兼容库（zhiqim_servlet）在LGPL3.0协议下开源：https://www.zhiqim.com/gitcan/zhiqim/zhiqim_servlet.htm
 *
 * This file is part of [zhiqim_servlet].
 * 
 * [zhiqim_servlet] is free software: you can redistribute
 * it and/or modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * [zhiqim_servlet] is distributed in the hope that it will
 * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with [zhiqim_servlet].
 * If not, see <http://www.gnu.org/licenses/>.
 */
package org.zhiqim.servlet;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import org.zhiqim.httpd.HttpContext;
import org.zhiqim.httpd.HttpSession;
import org.zhiqim.httpd.HttpSessionManager;
import org.zhiqim.httpd.HttpSessionUser;
import org.zhiqim.kernel.paging.PageBuilder;
import org.zhiqim.kernel.paging.PageResult;
import org.zhiqim.kernel.util.Asserts;
import org.zhiqim.kernel.util.Lists;

/**
 * ZML会话管理器
 *
 * @version v1.0.0 @author zouzhigang 2017-1-6 新建与整理
 */
public class ZmlSessionManager implements HttpSessionListener, HttpSessionManager
{
    private final HttpContext context;
    private HashMap<String, HttpSession> sessionMap = new HashMap<>();
    
    public ZmlSessionManager(HttpContext context)
    {
        this.context = context;
    }
    
    @Override
    public void sessionCreated(HttpSessionEvent event)
    {
        javax.servlet.http.HttpSession session = event.getSession();
        sessionMap.put(session.getId(), new ZmlSession(context, session));
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent event)
    {
        sessionMap.remove(event.getSession().getId());
    }
    
    /**************************************************/
    //设置 & 获取 & 失效 会话
    /**************************************************/
    
    @Override/** 设置会话 */
    public void setSession(HttpSession session)
    {
        throw Asserts.exception("该方法禁止在Servlet容器中调用，因为获取不到会话管理权限");
    }
    
    @Override/** 获取会话 */
    public HttpSession getSession(String sessionId)
    {
        return sessionMap.get(sessionId);
    }
    
    @Override/** 判断会话是否存在 */
    public boolean hasSession(String sessionId)
    {
        return sessionMap.containsKey(sessionId);
    }
    
    @Override/** 删除一个会话，指定会话编号 */
    public void invalidateSession(String sessionId)
    {//注：从sessionMap中删除由sessionDestroyed处理
        HttpSession session = sessionMap.get(sessionId);
        if (session == null)
            return;
        
        session.invalidate();
    }
    
    /******************************************************************************************/
    //会话查询和统计
    /******************************************************************************************/
    
    /** 查会话数 */
    public int size()
    {
        return sessionMap.size();
    }
    
    /** 获取会话列表 */
    public Collection<HttpSession> getSessionList()
    {
        return sessionMap.values();
    }
    
    /** 获取会话登录用户列表 */
    public PageResult<HttpSession> getSessionPage(int pageNo, int pageSize)
    {
        int size = sessionMap.size();
        if (size == 0)
            return PageBuilder.newResult(pageNo, pageSize);
        
        int pageNoMax = (size-1) / pageSize + 1;
        if (pageNo < 1) pageNo = 1;
        if (pageNo > pageNoMax) pageNo = pageNoMax;
        
        int start = (pageNo-1) * pageSize;
        int end = pageNo * pageSize;
        
        ArrayList<HttpSession> list = new ArrayList<HttpSession>();
        Iterator<HttpSession> it = sessionMap.values().iterator();
        for (int i=0;it.hasNext();i++)
        {
            HttpSession s = it.next();
            if (i < start)
                continue;
            else if (i >= end)
                break;
            else
                list.add(s);
        }
        
        list.trimToSize();
        return PageBuilder.newResult(size, pageNo, pageSize, list);
    }
    
    /******************************************************************************************/
    //会话用户查询和统计
    /******************************************************************************************/
    
    /** 查用户数，有登录状态 */
    public <T extends HttpSessionUser> int sizeUser(Class<T> clazz)
    {
        int size = 0;
        for (HttpSession s : sessionMap.values())
        {
            if (s.hasSessionUser(clazz))
                size++;
        }

        return size;
    }
    
    /** 是否有会话名称对应的会话 */
    public <T extends HttpSessionUser> boolean hasSessionName(String sessionName, Class<T> clazz)
    {
        Asserts.notNull(sessionName , "sessionName");
        
        for (HttpSession s : sessionMap.values())
        {
            HttpSessionUser su = s.getSessionUser(clazz);
            if (su == null)
                continue;
            
            if (sessionName.equals(su.getSessionName()))
                return true;
        } 
        
        return false;
    }
    
    /** 获取会话登录用户列表，指定会话用户类名（如前后端共用session管理器的情况） */
    public <T extends HttpSessionUser> List<T> getSessionUserList(Class<T> clazz)
    {
        List<T> list = new ArrayList<>();
        for (HttpSession s : sessionMap.values())
        {
            T sessionUser = s.getSessionUser(clazz);
            if (sessionUser != null)
                list.add(sessionUser);
        }
    
        return Collections.unmodifiableList(Lists.trim(list));
    }
    
    /** 获取会话登录用户分页信息，指定会话用户类名（如前后端共用session管理器的情况） */
    public <T extends HttpSessionUser> PageResult<T> getSessionUserPage(int pageNo, int pageSize, Class<T> clazz)
    {
        List<T> list = new ArrayList<>();
        for (HttpSession s : sessionMap.values())
        {
            T sessionUser = s.getSessionUser(clazz);
            if (sessionUser != null)
                list.add(sessionUser);
        }

        list = Collections.unmodifiableList(Lists.trim(list));
        return PageBuilder.pageResult(pageNo, pageSize, list);
    }
    
    /****************************************************************/
    //不支持的方法 HttpSessionManager
    /****************************************************************/

    @Override
    public void setSessionTimeout(int sessionTimeout)
    {
    }

    @Override
    public int getSessionTimeout()
    {
        return 0;
    }

    @Override
    public void setSessionIdName(String sessionCookieName)
    {
    }

    @Override
    public String getSessionIdName()
    {
        return null;
    }

    @Override
    public void setSessionParameter(String sessionParameter)
    {
    }

    @Override
    public void open()
    {
    }

    @Override
    public void close()
    {
    }
}
